package org.alvin.gencode.run.code;

import com.google.common.base.CaseFormat;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.alvin.code.jdbc.JDBCBaseDao;
import org.alvin.code.jdbc.utils.SqlUtil;
import org.alvin.gencode.run.service.JDBC2MbTypeService;
import org.alvin.mini_inject.annotations.MiniComponent;
import org.alvin.mini_inject.annotations.MiniInject;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@MiniComponent
public class PostgreCodeDao extends JDBCBaseDao implements ICodeDao {

    @MiniInject
    private JDBC2MbTypeService jdbc2MbTypeService ;


    public static Map<String, String> dbTypeMap = Maps.newHashMap();

    static {
        dbTypeMap.put("DATE", "java.util.Date");
        dbTypeMap.put("TIME", "java.util.Date");
        dbTypeMap.put("TIMESTAMP", "java.util.Date");
        dbTypeMap.put("TIMESTAMP WITHOUT TIMEZONE", "java.util.Date");
        dbTypeMap.put("TIMESTAMP WITH TIMEZONE", "java.util.Date");
        dbTypeMap.put("VARCHAR", "java.lang.String");
        dbTypeMap.put("TEXT", "java.lang.String");
        dbTypeMap.put("INT2", "java.lang.Integer");
        dbTypeMap.put("INT4", "java.lang.Integer");
        dbTypeMap.put("INT8", "java.lang.Long");
        dbTypeMap.put("FLOAT4", "java.lang.Float");
        dbTypeMap.put("FLOAT8", "java.lang.Double");
        dbTypeMap.put("NUMERIC", "java.math.BigDecimal");
        dbTypeMap.put("BOOL", "java.lang.Boolean");

//        dbTypeMap.put("DATE", "java.time.LocalDate");
//        dbTypeMap.put("TIME", "java.time.LocalTime");
//        dbTypeMap.put("TIMESTAMP WITHOUT TIMEZONE", "java.time.LocalDateTime");
//        dbTypeMap.put("TIMESTAMP WITH TIMEZONE", "java.time.OffsetDateTime");
//        dbTypeMap.put("VARCHAR", "java.lang.String");
//        dbTypeMap.put("TEXT", "java.lang.String");
//        dbTypeMap.put("INT2", "java.lang.Integer");
//        dbTypeMap.put("INT4", "java.lang.Integer");
//        dbTypeMap.put("INT8", "java.lang.Long");
//        dbTypeMap.put("FLOAT4", "java.lang.Float");
//        dbTypeMap.put("FLOAT8", "java.lang.Double");
//        dbTypeMap.put("NUMERIC", "java.math.BigDecimal");
//        dbTypeMap.put("BOOL", "java.lang.Boolean");
    }


    /**
     * @功能描述: 查询表名列表
     */
    @Override
    public List<Table> queryTables(CodeCond cond) throws SQLException {
        // SELECT tablename FROM pg_tables where tablename not like 'pg_%' and tablename not like 'sql_%'  order by tablename asc;
        StringBuilder sb = new StringBuilder();
        // where relname = '" + cond.getT_name() + "'
        sb.append("select\n" +
                "\trelname as t_name,\n" +
                "\tcast(obj_description(oid, 'pg_class') as varchar) as comment\n" +
                "from\n" +
                "\tpg_class c\n" +
                "where relpersistence = 'p' and cast(obj_description(oid, 'pg_class') as varchar) is not null and relname not in "+ SqlUtil.ArrayToIn(cond.getTableNameNotIn()));

        System.out.println(sb.toString());
        return this.queryList(sb.toString(), cond, Table.class).stream().map(item -> {
            item.setCls_upp(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, item.getT_name()));
            item.setC_name(item.getComment());
            return item;
        }).collect(Collectors.toList());

    }

    /**
     * @功能描述: 查询字段名列表
     */

    @Override
    public List<Field> queryFields(CodeCond cond) throws SQLException {
        String sql = "select\n" +
                "\ta.attnum as \"index\",\n" +
                "\tc.relname as \"table_name\",\n" +
                "\tcast(obj_description(relfilenode, 'pg_class') as varchar) as \"table_commom\",\n" +
                "\ta.attname as \"NAME\",\n" +
                "\tt.typname as \"type\", \n" +
                "\td.description as \"COMMENT\"\n" +
                "\t,\n" +
                "\t(case when a.attlen > 0 then a.attlen else a.atttypmod - 4 end) as \"length\"\n" +
                "from\n" +
                "\tpg_class c,\n" +
                "\tpg_attribute a ,\n" +
                "\tpg_type t,\n" +
                "\tpg_description d\n" +
                "where\n" +
                "\tc.relname = '" + cond.getT_name_eq() + "'\n" +
                "\tand a.attnum>0\n" +
                "\tand a.attrelid = c.oid\n" +
                "\tand a.atttypid = t.oid\n" +
                "\tand d.objoid = a.attrelid\n" +
                "\tand d.objsubid = a.attnum\n" +
                "order by\n" +
                "\tc.relname desc,\n" +
                "\ta.attnum asc";
        System.out.println(sql );
        List<Field> list = this.queryList(sql, cond, Field.class);
        //主键
        sql = "SELECT\n" +
                "    pg_constraint.conname AS pk_name,\n" +
                "    pg_attribute.attname AS colname,\n" +
                "    pg_type.typname AS typename\n" +
                "FROM\n" +
                "    pg_constraint\n" +
                "INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid\n" +
                "INNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid\n" +
                "AND pg_attribute.attnum = pg_constraint.conkey [ 1 ]\n" +
                "INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid\n" +
                "WHERE\n" +
                "    pg_class.relname = '" + cond.getT_name_eq() + "'\n" +
                "AND pg_constraint.contype = 'p'";
        System.out.println(sql );
        List<Map<String, Object>> pks = this.queryList(sql, cond);

        for (Map<String, Object> pk : pks) {
            for (Field f : list) {
                if (f.getName().toLowerCase().equals(pk.get("colname").toString())) {
                    f.setColumn_key("PRI");
                    break;
                }
            }
        }
        //类型映射
        //大写部分字段
        for (Field f : list) {
            f.setDbType(f.getType().toUpperCase());
            String typeName = dbTypeMap.get(f.getDbType());
            if (typeName == null) {
                typeName = "'无效数据类型'";
            }
            f.setAllTypeName(typeName);
            f.setMb_db_type(this.jdbc2MbTypeService.getType(f.getDbType().toUpperCase()));
        }
        return list;
    }


}



